package com.giteelou.antlr.ps.man;

import com.giteelou.antlr.ps.MyParser;
import com.giteelou.antlr.ps.MyParserBaseVisitor;
import com.giteelou.antlr.ps.man.symbol.Variable;
import com.giteelou.antlr.ps.man.type.PrimitiveType;
import com.giteelou.antlr.ps.man.type.Type;

/**
 * 计算
 */
public class ASTEvaluate extends MyParserBaseVisitor<Object> {

    private final Semantics semantics;

    public ASTEvaluate(Semantics semantics) {
        this.semantics = semantics;
    }

    @Override
    public Object visitVariableDeclaration(MyParser.VariableDeclarationContext ctx) {
        Object ret = null;
        for (MyParser.VariableDeclaratorContext vCtx : ctx.variableDeclarators().variableDeclarator()) {
            ret = visitVariableDeclarator(vCtx);
        }
        return ret;
    }

    @Override
    public Object visitVariableAssignment(MyParser.VariableAssignmentContext ctx) {
        return visitVariableDeclarator(ctx.variableDeclarator());
    }

    @Override
    public Object visitVariableDeclarator(MyParser.VariableDeclaratorContext ctx) {
        MyParser.VariableInitializerContext viCtx = ctx.variableInitializer();
        if (viCtx == null) {
            return null;
        }
        return visitVariableInitializer(viCtx);
    }

    @Override
    public Object visitVariableInitializer(MyParser.VariableInitializerContext ctx) {
        return visitLiteral(ctx.literal());
    }

    @Override
    public Object visitLiteral(MyParser.LiteralContext ctx) {
        if (ctx.DECIMAL_LITERAL() != null) {
            String text = ctx.DECIMAL_LITERAL().getText().toUpperCase();
            if (text.endsWith("L")) {
                return Long.valueOf(text.substring(0, text.length() - 1));
            }
            Type type = semantics.nodeTypes.get(ctx);
            if (type == PrimitiveType.BYTE) {
                return Byte.valueOf(text);
            }
            if (type == PrimitiveType.SHORT) {
                return Short.valueOf(text);
            }
            if (type == PrimitiveType.CHAR) {
                return (char) Integer.parseInt(text);
            }
            if (type == PrimitiveType.FLOAT) {
                return Float.valueOf(text);
            }
            if (type == PrimitiveType.DOUBLE) {
                return Double.valueOf(text);
            }
            return Integer.valueOf(text);
        } else if (ctx.FLOAT_LITERAL() != null) {
            if (semantics.nodeTypes.get(ctx) == PrimitiveType.FLOAT) {
                return Float.valueOf(ctx.FLOAT_LITERAL().getText());
            }
            return Double.valueOf(ctx.FLOAT_LITERAL().getText());
        } else if (ctx.BOOL_LITERAL() != null) {
            return Boolean.valueOf(ctx.BOOL_LITERAL().getText());
        } else if (ctx.CHAR_LITERAL() != null) {
            Type type = semantics.nodeTypes.get(ctx);
            char c = ctx.CHAR_LITERAL().getText().charAt(1);
            if (type == PrimitiveType.BYTE) {
                return (byte) c;
            }
            if (type == PrimitiveType.SHORT) {
                return (short) c;
            }
            if (type == PrimitiveType.INT) {
                return (int) c;
            }
            if (type == PrimitiveType.LONG) {
                return (long) c;
            }
            if (type == PrimitiveType.FLOAT) {
                return (float) c;
            }
            if (type == PrimitiveType.DOUBLE) {
                return (double) c;
            }
            return c;
        }
        return null;
    }

}
